/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.meetic.shuffle;

import ohos.agp.components.AttrSet;
import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.database.DataSetSubscriber;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * Shuffle容器
 */
public abstract class ShuffleProviderComponent extends ComponentContainer
    implements Component.LayoutRefreshedListener, Component.BindStateChangedListener,
    Component.DrawTask, ComponentContainer.ArrangeListener {
  /**
   * Shuffle最大显示数
   */
  public static final int DEFAULT_MAX_VISIBLE = 3;

  private static final String MAX_VISIBLE_NUM = "maxVisibleNum";

  private int mMaxVisible;

  private final List<Component> mChildComponents = new ArrayList<>();

  private BaseItemProvider mProvider;

  private boolean mIsRegistered;

  private boolean isShuffleOverlap = false;


  /**
   * 构造方法
   *
   * @param context 上下文
   */
  public ShuffleProviderComponent(Context context) {
    this(context, null);
  }

  /**
   * 构造方法
   *
   * @param context 上下文
   * @param attrSet 自定义属性
   */
  public ShuffleProviderComponent(Context context, AttrSet attrSet) {
    this(context, attrSet, null);
  }

  /**
   * 构造方法
   *
   * @param context   上下文
   * @param attrSet   自定义属性
   * @param styleName 风格样式
   */
  public ShuffleProviderComponent(Context context, AttrSet attrSet, String styleName) {
    super(context, attrSet, styleName);
    mMaxVisible = AttrUtils.getIntFromAttr(attrSet, MAX_VISIBLE_NUM, DEFAULT_MAX_VISIBLE);
    setArrangeListener(this);
    setBindStateChangedListener(this);
    setLayoutRefreshedListener(this);
    addDrawTask(this);
  }

  @Override
  public void onComponentBoundToWindow(Component component) {
    if (mProvider != null && !mIsRegistered) {
      mIsRegistered = true;
      mProvider.addDataSubscriber(subscriber);
    }
  }

  @Override
  public void onComponentUnboundFromWindow(Component component) {
    if (mProvider != null && mIsRegistered) {
      mIsRegistered = false;
      mProvider.removeDataSubscriber(subscriber);
    }
  }

  @Override
  public Component getComponentAt(int index) {
    if (index < 0 || index >= mChildComponents.size()) {
      return null;
    }
    return mChildComponents.get(index);
  }

  @Override
  public boolean onArrange(int left, int top, int right, int bottom) {
    for (int i = 0; i < getChildCount(); i++) {
      Component childComponent = getComponentAt(i);
      if (childComponent != null) {
        switch (i) {
          case 0:
            childComponent.setContentPositionX((getWidth() - childComponent.getWidth()) / 2f);
            childComponent.setContentPositionY((getHeight() - childComponent.getHeight()) / 2f);
            break;
          case 1:
            if (isShuffleOverlap) {
              childComponent.setContentPositionX((getWidth() - childComponent.getWidth()) / 2f - 8);
              childComponent.setContentPositionY((getHeight() - childComponent.getHeight()) / 2f - 15);
            } else {
              childComponent.setContentPositionX((getWidth() - childComponent.getWidth()) / 2f + 8);
              childComponent.setContentPositionY((getHeight() - childComponent.getHeight()) / 2f + 15);
            }
            break;
          case 2:
            if (isShuffleOverlap) {
              childComponent.setContentPositionX((getWidth() - childComponent.getWidth()) / 2f - 18);
              childComponent.setContentPositionY((getHeight() - childComponent.getHeight()) / 2f - 30);
            } else {
              childComponent.setContentPositionY((getHeight() - childComponent.getHeight()) / 2f + 30);
              childComponent.setContentPositionX((getWidth() - childComponent.getWidth()) / 2f + 18);
            }
            break;
        }
      }
    }
    return false;
  }

  /**
   * 获取当前被选中的item组件
   *
   * @return 被选中的组件
   */
  public abstract Component getSelectedComponent();

  /**
   * Shuffle重叠方式
   *
   * @param isShuffleOverlap
   */
  public void setShuffleOverlap(boolean isShuffleOverlap) {
    this.isShuffleOverlap = isShuffleOverlap;
  }

  /**
   * 获取适配器
   *
   * @return 适配器
   */
  public BaseItemProvider getItemProvider() {
    return mProvider;
  }

  /**
   * 获取最大显示child component数
   *
   * @return child component
   */
  public int getMaxVisible() {
    return mMaxVisible;
  }

  /**
   * 设置最大显示child component数
   *
   * @param maxVisible 最大显示child component数
   */
  public void setMaxVisible(int maxVisible) {
    this.mMaxVisible = maxVisible;
  }

  /**
   * 设置适配器
   *
   * @param itemProvider 适配器
   */
  public void setItemProvider(BaseItemProvider itemProvider) {
    mProvider = itemProvider;
    if (mProvider != null && !mIsRegistered) {
      mIsRegistered = true;
      mProvider.addDataSubscriber(subscriber);
    }
    mChildComponents.clear();
    if (getChildCount() > 0) {
      removeAllComponents();
    }
    addAllItem();
  }

  private void addAllItem() {
    if (mProvider == null) {
      return;
    }
    for (int i = 0; i < mProvider.getCount(); i++) {
      boolean isAddToParent = false;
      Component childComponent = null;
      if (i < getChildCount()) {
        childComponent = getComponentAt(i);
      }
      if (childComponent == null) {
        isAddToParent = true;
      }
      childComponent = mProvider.getComponent(i, childComponent, this);
      if (isAddToParent) {
        mChildComponents.add(childComponent);
        if (getChildCount() < mMaxVisible) {
          addComponent(childComponent, 0);
        }
      }
    }
  }

  private void insertItem(int position) {
    Component addComponent = mProvider.getComponent(position, null, this);
    mChildComponents.add(addComponent);
    for (int i = 0; i < mChildComponents.size(); i++) {
      mProvider.getComponent(i, mChildComponents.get(i), this);
    }
  }

  private void removeItem(int position) {
    if (position >= 0 && position < mChildComponents.size()) {
      Component removeComponent = mChildComponents.get(position);
      mChildComponents.remove(removeComponent);
      int childIndex = getChildIndex(removeComponent);
      if (childIndex >= 0) {
        removeComponentAt(childIndex);
      }
      int childCount = getChildCount();
      if (childCount < mMaxVisible && childCount < mChildComponents.size()) {
        addComponent(mChildComponents.get(getChildCount()), 0);
      }
    }
  }

  private DataSetSubscriber subscriber =
      new DataSetSubscriber() {
        @Override
        public void onChanged() {
        }

        @Override
        public void onItemInserted(int position) {
          insertItem(position);
        }

        @Override
        public void onItemRemoved(int position) {
          removeItem(position);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
        }
      };
}
